<template>
    <el-form :inline="inline"
             size="mini"
             :model="form"
             ref="dynamicValidateForm"
             :label-width="labelWidth"
             v-loading="formLoading"
             :label-position="labelPosition"
             @submit.native.prevent
    >

            <el-row type="flex" v-for="(rowItem,rowIndex) in computedLayout" :key="rowIndex">
                <el-col :span="24/rowItem > layoutColMax ? (inline?layoutColMax:24/rowItem): 24/rowItem" v-for="(colItem,colIndex) in rowItem" :key="colIndex">
                    <template v-for="(item, formItemIndex) in [computedFormItems[arrayBeforeIndexSum(rowIndex,computedLayout) + colItem-1]]"
                              >
                        <el-form-item
                            v-if="isShow(item,form)"
                            :label="getLabel(item,form)"
                            :key="formItemIndex"
                            :prop="getFieldName(item)"
                            :rules="getRules(item)"
                    >
                        <el-input v-if="item.element.type == 'text'"
                                  v-model="form[getFieldName(item)]"
                                  :placeholder="item.element.placeholder"
                                  :disabled="getDisabled(item)"
                                  :readonly="item.element.readonly"
                                  :title="getTitle(item)"
                                  clearable>
                        </el-input>
                        <el-input v-else-if="item.element.type == 'textarea'"
                                  type="textarea"
                                  :placeholder="item.element.placeholder"
                                  :disabled="getDisabled(item)"
                                  :readonly="item.element.readonly"
                                  v-model="form[getFieldName(item)]" clearable>
                        </el-input>
                        <el-input-number v-else-if="item.element.type == 'inputNumber'"
                                         v-model="form[getFieldName(item)]" controls-position="right"
                                         :min="getInputNumber(item).min"
                                         :max="getInputNumber(item).max"
                                         :disabled="getDisabled(item)"
                                         :step="item.element.inputNumber?(item.element.inputNumber.step||1):1"
                                         :precision="item.element.inputNumber?(item.element.inputNumber.precision||0):0"
                                         :readonly="item.element.readonly"
                        ></el-input-number>
                        <SelectDict v-else-if="item.element.type == 'selectDict'"
                                    :group-code="item.element.selectDict.groupCode"
                                    :placeholder="item.element.placeholder"
                                    v-on:dictCode="(dictCode)=> {$set(form,item.field.name+'__code',dictCode)}"
                                    :disabled="getDisabled(item)"
                                    :readonly="item.element.readonly"
                                    v-model="form[getFieldName(item)]">
                        </SelectDict>
                        <InputSelectTree v-else-if="item.element.type == 'inputSelectTree'"
                                         v-model="form[getFieldName(item)]"
                                         :label-text="form[getFieldName(item) + '__label']"
                                         :placeholder="item.element.placeholder"
                                         :disabled="getDisabled(item)"
                                         :readonly="item.element.readonly"
                                         :tree-data-url="handleUrl(item.element.inputSelectTree.dataUrl)">

                        </InputSelectTree>
                        <InputSelectIcon v-else-if="item.element.type == 'inputSelectIcon'"
                                         v-model="form[getFieldName(item)]"
                                         :disabled="getDisabled(item)"
                                         :readonly="item.element.readonly"
                                         :placeholder="item.element.placeholder">

                        </InputSelectIcon>
                            <SelectYesNo v-else-if="item.element.type == 'selectYesNo'"
                                        :placeholder="item.element.placeholder"
                                        :disabled="getDisabled(item)"
                                        :readonly="item.element.readonly"
                                         :show-empty="item.element.selectYesNo.showEmpty"
                                         :empty-label="item.element.selectYesNo.emptyLabel"
                                         :empty-value="item.element.selectYesNo.emptyValue"
                                        v-model="form[getFieldName(item)]">
                            </SelectYesNo>
                        <el-switch v-else-if="item.element.type == 'switch'"
                                   v-model="form[getFieldName(item)]"
                                   :disabled="getDisabled(item)"
                                   :readonly="item.element.readonly"
                                   :active-text="item.element.switch ? item.element.switch.activeText: '是'"
                                   :inactive-text="item.element.switch ? item.element.switch.inactiveText: '否'"
                        >

                        </el-switch>
                            <el-color-picker v-else-if="item.element.type == 'colorPicker'"
                                             v-model="form[getFieldName(item)]"
                                             :predefine="item.element.colorPicker ? item.element.colorPicker.predefine: null"
                                             :color-format="item.element.colorPicker ? item.element.colorPicker.colorFormat: 'hex'"
                                             :show-alpha="item.element.colorPicker ? item.element.colorPicker.showAlpha: false"
                                             :disabled="getDisabled(item)">

                            </el-color-picker>
                        <Select v-else-if="item.element.type == 'select'"
                                v-model="form[getFieldName(item)]"
                                :readonly="item.element.readonly"
                                :disabled="getDisabled(item)"
                                :show-empty="item.element.select.showEmpty"
                                v-on:selectData="(data)=> {$set(form,item.field.name+'__selectData',data)}"
                                :url="handleUrl(item.element.select.url)"
                                :data="item.element.select?item.element.select.data: null"
                                :group-url="item.element.select.groupUrl"
                                :group-data="item.element.select.groupData"
                                :option-prop="item.element.select.optionProp"
                                :group-prop="item.element.select.groupProp"
                        ></Select>
                            <SelectLocal v-else-if="item.element.type == 'selectLocal'"
                                    v-model="form[getFieldName(item)]"
                                    :readonly="item.element.readonly"
                                    :disabled="getDisabled(item)"
                                    :show-empty="item.element.selectLocal.showEmpty"
                                    v-on:selectData="(data)=> {$set(form,item.field.name+'__selectData',data)}"
                                    :data="item.element.selectLocal.data"
                                    :group-data="item.element.selectLocal.groupData"
                                    :option-prop="item.element.selectLocal.optionProp"
                                    :group-prop="item.element.selectLocal.groupProp"
                            ></SelectLocal>
                            <RadioGroup v-else-if="item.element.type == 'radioGroup'"
                                    v-model="form[getFieldName(item)]"
                                    :readonly="item.element.readonly"
                                    :disabled="getDisabled(item)"
                                    v-on:selectData="(data)=> {$set(form,item.field.name+'__selectData',data)}"
                                    :url="handleUrl(item.element.radioGroup.url)"
                                        :radio-type="item.element.radioGroup.radioType"
                                    :data="item.element.radioGroup.data"
                                    :option-prop="item.element.radioGroup.optionProp"
                            ></RadioGroup>
                            <CheckBoxGroup v-else-if="item.element.type == 'checkBoxGroup'"
                                        v-model="form[getFieldName(item)]"
                                        :readonly="item.element.readonly"
                                        :disabled="getDisabled(item)"
                                        v-on:selectData="(data)=> {$set(form,item.field.name+'__selectData',data)}"
                                        :url="handleUrl(item.element.checkBoxGroup.url)"
                                           :check-box-type="item.element.checkBoxGroup.checkBoxType"
                                        :data="item.element.radioGroup.data"
                                        :option-prop="item.element.checkBoxGroup.optionProp"
                            ></CheckBoxGroup>
                            <el-checkbox  v-else-if="item.element.type == 'checkBox'"
                                          v-model="form[getFieldName(item)]"
                                          :readonly="item.element.readonly"
                                          :disabled="getDisabled(item)"
                            >
                                {{item.element.checkBox?$_object_getValue(item.element.checkBox.txt):null}}
                            </el-checkbox>
                        <SelectRemote v-else-if="item.element.type == 'selectRemote'"
                                      v-model="form[getFieldName(item)]"
                                      :label="form[getFieldName(item) + '__label']"
                                      :disabled="getDisabled(item)"
                                      :readonly="item.element.readonly"
                                      :url="handleUrl(item.element.selectRemote.url)"
                                      :query-prop="item.element.selectRemote.queryProp"
                                      :option-prop="item.element.selectRemote.optionProp"
                        ></SelectRemote>
                        <DateTimePicker v-else-if="item.element.type == 'date'"
                                        v-model="form[getFieldName(item)]"
                                        :disabled="getDisabled(item)"
                                        :readonly="item.element.readonly"
                                        :type="item.element.date ?item.element.date.type:undefined"
                                        :format="item.element.date ?item.element.date.format:undefined"
                                        :time-is-range="item.element.date ?item.element.date.timeIsRange:undefined"
                                        :value-format="item.element.date ?item.element.date.valueFormat:undefined"
                                        v-on:start="(val)=>{form[item.field.startName || item.field.name + 'Start'] = val}"
                                        v-on:end="(val)=>{form[item.field.endName || item.field.name + 'End'] = val}"
                        ></DateTimePicker>
                        <InputButton v-else-if="item.element.type == 'inputButton'"
                                     v-model="form[getFieldName(item)]"
                                     :placeholder="item.element.placeholder"
                                     :disabled="getDisabled(item)"
                                     :readonly="item.element.readonly"
                                     :title="getTitle(item)"
                                     :b-click="item.element.inputButton.bClick"
                                     clearable>
                        </InputButton>
                        <template v-else-if="item.element.type == 'txt'">
                            {{$_object_getValue(form,getFieldName(item),form)}}
                        </template>
                        <template v-else-if="item.element.type == 'button'">
                            <el-button v-if="$_object_isObject(item.element.button)"
                                       :type="item.element.button.type || aiButtonStyle(item.element.button.label).type || 'primary'"
                                       :icon="item.element.button.icon || aiButtonStyle(item.element.button.label).icon "
                                       @click="buttonClick(item.element.button)"
                                       :native-type="item.element.button.action == 'submit' ? 'submit': null"
                                       :loading="localButtonLoading[item.element.button.code]"
                                       :disabled="isButtonDisabled(item.element.button)"
                                       :title="getTitle(item.element.button)"
                            >{{item.element.button.label}}</el-button>
                            <template v-else-if="$_array_isArray(item.element.button)">
                                <el-button v-for="(buttonItem,elementButtonIndex) in item.element.button" :key="elementButtonIndex"
                                           :type="buttonItem.type || aiButtonStyle(buttonItem.label).type || 'primary'"
                                           :icon="buttonItem.icon || aiButtonStyle(buttonItem.label).icon "
                                           @click="buttonClick(buttonItem)"
                                           :native-type="buttonItem.action == 'submit' ? 'submit': null"
                                           :loading="localButtonLoading[buttonItem.code]"
                                           :disabled="isButtonDisabled(buttonItem)"
                                           :title="getTitle(buttonItem)"
                                >{{buttonItem.label}}</el-button>
                            </template>
                        </template>
                        <!-- 文件上传 -->
                        <template v-else-if="item.element.type == 'upload'">
                            <file-upload v-if="item.element.upload.type == 'upload'"
                                         v-model="form[getFieldName(item)]"
                                         :disabled="getDisabled(item)"
                                         :accept="item.element.upload.accept"
                                         :data="item.element.upload.data"
                                         :limit="item.element.upload.limit"
                                         :show-file-list="item.element.upload.showFileList"
                                         :list-type="item.element.upload.listType"
                                         :multiple="item.element.upload.multiple"
                                         :name="item.element.upload.name"
                                         :action="item.element.upload.action"
                                         :null-action-message="item.element.upload.nullActionMessage"
                                         :response-value-format="item.element.upload.responseValueFormat"
                                         v-on:onChange="(val)=>{form[item.field.name + '__fileData'] = val}"
                                         :auto-upload="item.element.upload.autoUpload"
                            >

                            </file-upload>
                            <file-upload-input v-else
                                               v-model="form[getFieldName(item)]"
                                               :placeholder="item.element.placeholder"
                                               :disabled="getDisabled(item)"
                                               :readonly="item.element.readonly"
                                               :accept="handleUploadInputAccept(item,form)"
                                               :data="item.element.upload.data"
                                               :name="item.element.upload.name"
                                               :action="item.element.upload.action"
                                               :null-action-message="item.element.upload.nullActionMessage"
                                               :response-value-format="item.element.upload.responseValueFormat"
                                               :show-preview-button="item.element.upload.showPreviewButton"
                                               clearable
                            >

                            </file-upload-input>
                        </template>
                        <template v-else-if="item.element.type == 'richEditor'">
                            <TinymceEditor ref="tinymceEditor" v-if="item.element.richEditor.type == 'tinymce'"
                                           v-model="form[getFieldName(item)]"
                                           :path="item.element.richEditor.path"
                                           :height="item.element.richEditor.height"
                                           :paste-auto-upload="item.element.richEditor.pasteAutoUpload"
                                           :upload-url="item.element.richEditor.uploadUrl"
                            >

                            </TinymceEditor>
                        </template>
                        <!-- 默认是文本类型 -->
                        <el-input v-else
                                  v-model="form[getFieldName(item)]"
                                  :placeholder="item.element.placeholder"
                                  :disabled="getDisabled(item)"
                                  :readonly="item.element.readonly"
                                  clearable>
                        </el-input>
                        <span style="color: #606266;" v-if="item.element.tips" v-html="item.element.tips"></span>
                    </el-form-item>

                    </template>
                </el-col>
            </el-row>


    </el-form>
</template>

<script>
    /* formItems 元素说明
        {
        // 表单对象
        field: {
            name: 'test1',// 表单的name
            value: '' // 初始值，也可以通过formData属性对象指定
            {value}__label: ''// 为inputSelectTree 等value对应的翻译，注意两个下划线，以防与后台属性冲突加了两个下划线,{value}是对name值的引用
        },
        // 页面元素
        element:{
         // 表单项类型可选择值 text=文本输入，
         // selectDict=字典下拉选择,button=按钮,inputNumber=数字,
         // inputSelectTree=输入选择树,date=日期或时间
         // upload=上传
            type: 'text',
            // 字典下拉选择时存在该对象
            selectDict:{
                groupCode: 'gender',
                showEmpty: true //是否显示请选择 选填
            },
            // 数字有效
            inputNumber:{
                min: 1,
                max: 100
            },
            inputSelectTree:{
                dataUrl: '',
            },
            // 日期举例，详情参见datetimepicker
             {
                field: {
                    name: 'startAt'
                },
                element:{
                    type: 'date',
                    label: '开始日期'
                }
            },
            // 上传,简单举例如下，更多参数参见web/common-util/src/components/upload/FileUpload.vue
            element:{
                type: 'upload',
                upload:{
                    type: 'uploadInput' //支持两个方式，uploadInput和upload
                },
                label: '广告内容地址',
                required: true
            }
            // 按钮时存在该对象,可以是一个以该对象为结构的数组
            button:{
                action: 'submit',// submit=表单提交，reset=重置表单，nav=导航到其它页面
                // submit时可用
                requestMethod:'get',
                // submit或nav时可用
                url:'',
                // 数组有效
                label: '测试'
            },
            label: '测试1',
        },
        // 验证规则
        rules:[
            {required: true, message: '测试1不能为空', trigger: 'blur'}
        ]
    }
    */
    import SelectDict from '../../components/common/SelectDict.vue'
    import arrayMixin from "../../mixin/ArrayMixin"
    import {cloneSimple,copyPropSimple,hasPropSimple} from '../../tools/ObjectTools.js'
    import objectMixin from "../../mixin/ObjectMixin"
    import InputSelectTree from '../../components/common/InputSelectTree.vue'
    import InputSelectIcon from '../../components/common/InputSelectIcon.vue'
    import Select from '../../components/common/Select.vue'
    import RadioGroup from '../../components/common/RadioGroup.vue'
    import SelectLocal from '../../components/common/SelectLocal.vue'
    import CheckBoxGroup from '../../components/common/CheckBoxGroup.vue'
    import SelectRemote from '../../components/common/SelectRemote.vue'
    import SelectYesNo from '../../components/common/SelectYesNo.vue'
    import DateTimePicker from '../../components/common/DateTimePicker.vue'
    import InputButton from '../../components/common/InputButton.vue'
    import FileUpload from '../../components/upload/FileUpload.vue'
    import FileUploadInput from '../../components/upload/FileUploadInput.vue'
    // 富文本编辑
    import TinymceEditor from '../../components/common/tinymceEditor/TinymceEditor.vue'

    import {aiButtonStyle} from "../../tools/StyleTools.js"
    export default {
        name: "Form",
        mixins:[objectMixin,arrayMixin],
        components:{
            SelectDict,
            InputSelectIcon,
            Select,
            RadioGroup,
            SelectLocal,
            CheckBoxGroup,
            SelectRemote,
            DateTimePicker,
            InputButton,
            SelectYesNo,
            FileUpload,
            FileUploadInput,
            TinymceEditor,
            InputSelectTree
        },
        props:{
            // left right top
            labelPosition: {
                type: String
            },
            // 布局一个数据[1,2,2],表示第一行1个第二行2个第三行2个
            layout: {
                type: Array,
                default: function () {
                    return []
                }
            },
            // 布局一个数字，指定几列，layout属性和该属性只能指定一个
            layoutColumnNum: {
                type: Number,
                default: null
            },
            // 布局的列最大值
            layoutColMax:{
                type: Number,
                default: 5
            },
            labelWidth:{
                type: String,
                default: '100px'
            },
            inline:{
                type: Boolean,
                default: false
            },
            // 可以通过总线触发表单提交操作，目前主要解决表格翻页,不可以响应
            submitBusKey:{
                type: String,
                default: null
            },
            submitSuccessText:{
                type:String,
                default: null
            },
            // 表单项定义信息
            formItems:{
                type: Array,
                default: function () {
                    return []
                }
            },
            // 表单项的值，供修改用
            //
            formData:{
                type: Object,
                default: null
            },
            // 表单加载状态
            loading:{
                type: Boolean,
                default:false
            },
            // 自定义按钮的loading状态，key为按钮的code,值为Boolean类型
            buttonLoading:{
                type: Object,
                default:function () {
                    return {}
                }
            },
            // 自定义按钮的禁用状态，key为按钮的code,值为Boolean类型
            buttonDisabled:{
                type: Object,
                default:function () {
                    return {}
                }
            },
            // 表单提交之前处理 参数为form,返回值为处理后的form
            formatForm:{
                type: Function
            },
            // 数据初始化的url，一般是修改时用
            initDataUrl:String,
            // 数据初始化的url请求完数据后，预处理回调,参数为数据实体对象而非响应对象，请依然返回实体
            handleInitData:Function,
            // 提交成功后回调，参数为数据实体对象而非响应对象
            submitSuccess:Function,
            submitError:Function,
            // 初始化完成后，触发提交操作，用于关联表格查询
            triggerSubmitOnInit:{
                type: Boolean,
                default: true
            }
        },
        computed:{
            // 合理化layout
            computedLayout (){
                let tempLayout = []
                let shouldTotal = this.formItems.length
                for(let i = 0;i<this.formItems.length;i++){
                    let item = this.formItems[i]
                    if(!item.element){
                        shouldTotal--
                    }
                }
                if (this.layout.length == 0) {

                    if(this.inline){
                        tempLayout.push(shouldTotal)
                    }else{
                        if(this.layoutColumnNum > 0){
                            if(this.layoutColumnNum > shouldTotal){
                                for (let i = 0; i < shouldTotal; i++) {
                                    tempLayout.push(1)
                                }
                            }else{
                                let col = Math.floor(shouldTotal/this.layoutColumnNum)
                                for (let i = 0; i < col; i++) {
                                    tempLayout.push(this.layoutColumnNum)
                                }
                                this.arrayAppendOneIfNeccesary(tempLayout,shouldTotal)
                            }
                        }else{
                            for (let i = 0; i < shouldTotal; i++) {
                                tempLayout.push(1)
                            }
                        }

                    }
                }else {
                     tempLayout = tempLayout.concat(this.layout)
                    this.arrayAppendOneIfNeccesary(tempLayout,shouldTotal)
                }
                return tempLayout
            },
            // 主要是为生成默认的按钮编码
            computedFormItems(){
                let r = []
                let length = this.formItems.length
                for(let i = 0;i<length;i++){
                    let item = this.formItems[i]
                    if(!item.element){
                        continue
                    }
                    if(item.element.type == 'button'){
                        if(this.$_object_isObject(item.element.button)){
                            if(item.element.button.code == undefined){
                                item.element.button.code = 'code' + i
                            }
                        }else if(this.$_array_isArray(item.element.button)){

                            let _length = item.element.button.length
                            for(let j = 0;j<_length;j++){
                                let button = item.element.button[j]
                                if(button.code == undefined){
                                    button.code = 'code' + i + '' + j
                                }
                            }
                        }
                    }
                    r.push(item)
                }
                return r
            }
        },
        data(){

            return {
                formLoading: this.loading,
                form: this.generateForm(),
                // 按钮loading 状态 submit为formItems.element.button.action的值，标识是哪个按钮
                localButtonLoading:this.buttonLoading,
                localButtonDisabled:this.buttonDisabled,
                // 分页对象,只针对submit
                pageQuery:null
            }
        },
        created(){
            this.busInit(true)
        },
        mounted(){
            this.initDataByUrl()
            this.triggerSubmitIfGetMethod()
        },
        destroyed () {
            this.busInit(false)
        },
        methods:{
            generateForm(){
                let form = {}
                this.formItems.forEach(item =>{
                    if(item.field){
                        form[item.field.name] = this.getFormItemValueByName(item.field.name) || item.field.value || null
                        // 扩展字段支持，label支持，主要是为了选择树回显翻译字面使用 ，当然也可以使用其它方式

                        for (let fieldKey in item.field) {
                            if(fieldKey.indexOf('__') >=0 ){
                                form[fieldKey] = this.getFormItemValueByName(fieldKey) || item.field[fieldKey] || null
                            }
                        }
                    }
                    // 处理范围选择的字段属性，目前是日期可以是范围选择，但控制v-model是一个数组，第一个表示开始，第二个表示结束，这里做一个转换，变为属性名
                    // 默认新增加的属性名是item.field.name + 'Start' 作为开发属性名，item.field.name + 'End' 作为结束属性名
                    // 也可以指定item.field.startName='xxx'和item.field.endName='xxx'来替换默认值
                    let isRange = false
                    if(item.element){
                        if(item.element.type == 'date' ||item.element.type == 'time'){
                            if(item.element.date && item.element.date.type.indexOf('range') > 0){
                                isRange = true
                            }else if(item.element.time && item.element.time.type.indexOf('range') > 0){
                                isRange = true
                            }
                        }
                    }
                    if (isRange) {
                        let startName = item.field.startName || item.field.name + 'Start'
                        let endName = item.field.endName || item.field.name + 'End'
                        let value = this.getFormItemValueByName(item.field.name)
                        if(value && this.$_array_isArray(value)){
                            form[startName] = value[0]
                            form[endName] = value[1]
                        }else {
                            form[startName] = null
                            form[endName] = null
                        }
                    }
                })
                return form
            },
            arrayAppendOneIfNeccesary(array, shouldTotal) {
                let  realTotal = 0
                array.forEach(item => {
                    realTotal += item
                })
                if(realTotal < shouldTotal){
                    for (let i = 0; i < shouldTotal - realTotal; i++) {
                        array.push(1)
                    }
                }
                else if(realTotal > shouldTotal){
                    throw new Error('layout总数多于元素总数');
                }
            },
            arrayBeforeIndexSum(index,array){
                let r = 0;
                for(let i = 0;i < index; i++){
                    r += array[i]
                }
                return r
            },
            getInputNumber(item){
                if(item.element.inputNumber){
                    return {
                        min: item.element.inputNumber.min !== undefined? item.element.inputNumber.min : 1,
                        max: item.element.inputNumber.max !== undefined ? item.element.inputNumber.max : 100
                    }
                }
                return {
                    min: 1,
                    max: 100
                }
            },
            handleUrl(url){
                if (typeof url == 'function') {
                    return url(this.form)
                }
                return url
            },
            getDisabled(item){
                if(item && item.element){
                    if(typeof item.element.disabled == 'function'){
                        return item.element.disabled(this.form)
                    }else{
                        return item.element.disabled
                    }
                }
                return false
            },
            getLabel(item) {
                if(typeof item.element.label == 'function'){
                    return item.element.label(this.form)
                }else{
                    return item.element.label
                }
            },
            getTitle(item){
                if(item){
                    if(item.title){
                        return item.title
                    }
                    if(item.element && item.element.title){
                        return item.element.title
                    }
                }
                return null
            },
            getFormItemValueByName(name){
                if(this.formData){
                    return this.formData[name]
                }
                return null
            },
            getFieldName(item){
                if(item.field){
                    return item.field.name
                }
                return null
            },
            getRules(item){
                let rules = item.rules
                if(!rules){
                    rules = []
                }
                if (hasPropSimple(item.element, 'required')) {
                    if(item.element.required === true){
                        rules.push({required: true, message: item.element.label + '不能为空', trigger: 'blur'})
                        rules.push({required: true, message: item.element.label + '不能为空', trigger: 'change'})
                    }else if(typeof item.element.required == 'function'){
                        rules.push({required: item.element.required(this.form), message: item.element.label + '不能为空', trigger: 'blur'})
                        rules.push({required: item.element.required(this.form), message: item.element.label + '不能为空', trigger: 'change'})
                    }
                }
                if (hasPropSimple(item.element, 'validator')) {
                    if(typeof item.element.validator == 'function'){
                        let validator = (rule, value, callback)=>{
                            item.element.validator(rule, value, callback,this.form)
                        }
                        rules.push({validator:validator, trigger: 'blur'})
                        rules.push({validator:validator, trigger: 'change'})
                    }
                }
                return rules
            },
            // 事件总线相关初始化,用于和table通信
            busInit(isBind){
                if(this.submitBusKey){
                    if(isBind){
                        this.$bus.$on(this.submitBusKey,this.handleBusSubmit)
                    }else {
                        this.$bus.$off(this.submitBusKey,this.handleBusSubmit)
                    }
                }
            },
            triggerSubmitIfGetMethod() {
                if (this.triggerSubmitOnInit) {
                    let button = this.getButton('submit')
                    if(button && button.requestMethod == 'get'){
                        this.submitForm(button)

                    }
                }

            },
            initDataByUrl(){
                if(this.initDataUrl){
                    this.formLoading = true
                    this.axios.get(this.initDataUrl).then(res => {
                        let data = res.data
                        if(this.handleInitData){
                            data = this.handleInitData(data)
                        }
                        for(let key in data){
                            this.setFormItem(key,data[key])
                        }
                    }).catch(error => {
                        if(error.response){
                            if(error.response.status == 404){
                                this.$message.error('数据不存在，请刷新数据再试')
                            }else {
                                this.$message.error(error.response.data.msg)
                            }
                        }else {
                            this.$message.error('网络错误或服务不可用')
                        }
                    }).finally(()=>{
                        this.formLoading = false
                    })
                }
            },
            handleBusSubmit(obj){
                if(obj){
                    if(obj.dataType == 'page'){
                        let page = obj.page
                        let button = this.getButton('submit')
                        this.submitForm(button,page)
                    }else if(obj.dataType == 'refresh'){
                        let button = this.getButton('submit')
                        this.submitForm(button)
                    }
                }

            },
            getButton(action){
                let buttonR = null
                this.formItems.forEach(item => {
                    let isBreak = false
                    if (!item.element) {
                        return true
                    }
                    if(this.$_object_isObject(item.element.button)){
                        if(action == item.element.button.action){
                            buttonR = item.element.button
                            isBreak = true
                        }
                    }else if(this.$_array_isArray(item.element.button)){
                        item.element.button.forEach(button => {
                            if(action == button.action){
                                buttonR = button
                                isBreak = true
                                return false
                            }
                        })
                    }
                    if(isBreak){
                        return false
                    }
                })
                return buttonR
            },
            buttonClick(button){
                if(typeof button.action == 'function'){
                    button.action(this.form,button.params)
                    return
                }
                switch (button.action) {
                    case 'submit':
                        this.submitForm(button)
                        break;
                    case 'reset':
                        this.resetForm()
                        break;
                    case 'nav':{
                        let url = button.url
                        if(typeof url == 'function'){
                            url = button.url(this.form)
                        }
                        this.$router.push(url)
                        break;
                    }

                }
            },
            getFormRef(){
                return this.$refs['dynamicValidateForm']
            },
            getFormData(){
                return this.form
            },
            validateAndSubmitForm(callback){

                this.$refs['dynamicValidateForm'].validate((valid) => {
                    if (valid) {
                        callback(this.form)
                    } else {
                        return false;
                    }
                });
            },
            submitForm(button,pageQuery) {
                if(!button) {
                    return
                }
                let form = this.form
                if(this.formatForm){
                    form = this.formatForm(form)
                }

                this.$refs['dynamicValidateForm'].validate((valid) => {
                    if (valid) {
                        let tempForm = cloneSimple(form,true)
                            if(pageQuery){
                                tempForm = copyPropSimple(tempForm,pageQuery)
                            }
                            let r = {}
                            for (let key in tempForm) {
                                if(key.indexOf('__') < 0){
                                    r[key] = tempForm[key]
                                }
                            }
                        // 去除扩展的字段们他们都是 以__两个下划线分割的
                            tempForm = r


                            this.$emit('submitLoading',true)
                            let method =  button.requestMethod || 'get'
                            let url = button.url
                            if(typeof url == 'function'){
                                url = button.url(form)
                                // 返回false 停止执行
                                if(url === false){
                                    return
                                }
                            }
                            let options = {
                                method:method,
                                url: url
                            }
                            if('get' == method){
                                options.params = tempForm
                            }else {
                                if(button.requestType == 'multipart'){
                                    let formData = new FormData()
                                    for (let key in tempForm){
                                        let value = tempForm[key]
                                        if(this.$_object_isObject(value) && value.raw){
                                            formData.append(key,value.raw)
                                        }else{
                                            formData.append(key,value)
                                        }
                                    }
                                    options.data = formData
                                }else{
                                    options.data = tempForm
                                }
                            }
                            this.setButtonLoading(button.code,true)
                            if(this.submitBusKey){
                                this.$bus.$emit(this.submitBusKey ,{dataType:'loading',loading: true})
                            }
                            this.axios(options).then(res =>{
                                if(this.submitBusKey){
                                    this.$bus.$emit(this.submitBusKey ,{dataType:'data',data: res.data})
                                }
                                this.$emit('submitData',res.data)
                                if(this.submitSuccessText){
                                    this.$message.success(this.submitSuccessText)
                                }else if(method == 'post'){
                                    this.$message.success('添加成功')
                                }else if(method == 'delete'){
                                    this.$message.success('删除成功')
                                }else if(method == 'put'){
                                    this.$message.success('更新成功')
                                }
                                if(typeof this.submitSuccess == 'function'){
                                    this.submitSuccess(res.data,form)
                                }
                            }).catch(error => {
                                if(this.submitBusKey){
                                    this.$bus.$emit(this.submitBusKey ,{dataType:'data',data: []})
                                }
                                if(typeof this.submitError == 'function'){
                                    this.submitError(error,form)
                                }
                                this.$emit('submitData',[])
                                if(error.response){
                                    if(error.response.status != 404){
                                        this.$message.error(error.response.data.msg)
                                    }
                                }else {
                                    this.$message.error('网络错误或服务不可用')
                                }
                            }).finally(()=>{
                                this.setButtonLoading(button.code,false)
                                if(this.submitBusKey){
                                    this.$bus.$emit(this.submitBusKey ,{dataType:'loading',loading: false})
                                }
                                this.$emit('submitLoading',false)
                            })
                    } else {
                        return false;
                    }
                });
            },
            emit(key,value){
                // 触发事件总线，目前是配合table完成请求与加载
                this.$bus.$emit(key ,value)
                this.$emit(key,value)
            },
            resetForm() {
                this.$refs['dynamicValidateForm'].resetFields();
                let tinymceEditor = this.$refs.tinymceEditor
                if(tinymceEditor){
                    if(this.$_array_isArray(tinymceEditor)){
                        tinymceEditor.forEach(item=>{
                            item.clearContent()
                        })
                    }else{
                        tinymceEditor.clearContent()
                    }
                }
            },
            aiButtonStyle(label){
                return aiButtonStyle(label)
            },
            // 设置值，请尽量使用该方法而不是去改变formData
            setFormItem(prop,value){
                if(this.form[prop] !== undefined){
                    this.form[prop] = value
                }
            },
            isShow(item){
                let show = false
                if(item.element){
                    if(item.element.show !== undefined){
                        if(typeof item.element.show == 'function'){
                            show = item.element.show(this.form)
                        }else{
                            show = item.element.show
                        }
                    }else{
                        show = true
                    }
                }
                return show
            },
            isButtonDisabled(button){
                if(button.disabled === true){
                    return true
                }else if(typeof button.disabled == 'function'){
                    return button.disabled()
                }else if(button.code){
                    return this.localButtonDisabled[button.code]
                }
                return false
            },
            // 设置按钮的加载状态，code为button中指定的code值，如果未指定则是默认的code+index索引字符串value=true或false
            // 也可以通过buttonLoading方式改变状态
            setButtonLoading(code,value){
                this.$set(this.localButtonLoading,code,value)
            },
            setButtonDisabled(code,value){
                this.$set(this.localButtonDisabled,code,value)
            },
            handleUploadInputAccept(item,form){
                if(typeof item.element.upload.accept == 'function'){
                    return item.element.upload.accept(form)
                }
                return item.element.upload.accept
            }
        },
        watch:{
            formData (val){
                for(let key in val){
                    if(this.form[key] !== undefined){
                        this.form[key] = val[key]
                    }
                }
            },
            buttonLoading(val){
                for(let prop in val){
                    if(this.localButtonLoading[prop] == undefined){
                        this.setButtonLoading(prop,val[prop])
                    }else  if(this.localButtonLoading[prop] != val[prop]){
                        this.setButtonLoading(prop,val[prop])
                    }
                }
            },
            buttonDisabled(val){
                for(let prop in val){
                    if(this.localButtonDisabled[prop] == undefined){
                        this.setButtonDisabled(prop,val[prop])
                    }else  if(this.localButtonDisabled[prop] != val[prop]){
                        this.setButtonDisabled(prop,val[prop])
                    }
                }
            },
            loading(val){
                this.formLoading = val
            },
            formItems(val){
                this.form = this.generateForm()
            },
            form(val){
                this.$emit('formChange',val)
            }
        }
    }
</script>

<style scoped>

</style>